package com.geniusk.system.utils;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import cn.hutool.json.JSONUtil;
import com.geniusk.common.enums.ResponseType;
import com.geniusk.common.exception.GraceException;
import com.geniusk.common.utils.IpUtil;
import com.geniusk.common.utils.ServletUtil;
import com.geniusk.security.enums.LoginSourceType;
import com.geniusk.system.model.pojo.LoginLog;
import com.geniusk.system.model.pojo.Role;
import com.geniusk.system.model.pojo.User;
import com.geniusk.security.core.DataPermission;
import com.geniusk.security.core.LoginUser;
import com.geniusk.security.enums.LoginType;
import com.geniusk.security.utils.SecurityUtil;
import com.geniusk.security.utils.TokenUtil;
import com.geniusk.system.service.LoginLogService;
import com.geniusk.system.service.MenuService;
import com.geniusk.system.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
@Service
public class LoginUtil {

    @Autowired
    TokenUtil tokenUtil;

    @Autowired
    UserService userService;

    @Autowired
    MenuService menuService;

    @Autowired
    LoginLogService loginLogService;

    /**
     * 获取用户登陆凭证
     * @param username 用户账户
     * @param password 用户密码
     * @return 登陆凭证
     */
    public String getLoginToken(String username, String password, LoginSourceType loginSourceType){

        User user = userService.selectUserByUserName(username);
        if(user == null){
            saveLoginLog(username, LoginType.LOGIN_FAIL.code(), LoginType.LOGIN_FAIL.msg(),loginSourceType.code());
            GraceException.display(ResponseType.USER_NOT_EXIST_ERROR);
        }
        LoginUser loginUser = getLoginUserByUser(user, loginSourceType);
        boolean matches = SecurityUtil.matchesPassword(password,user.getPassword());
        if(!matches){
            saveLoginLog(username, LoginType.LOGIN_FAIL.code(), LoginType.LOGIN_FAIL.msg(),loginSourceType.code());
            GraceException.display(ResponseType.USER_PARAMS_ERROR);
        }else {
            setUserAgent(loginUser);
            saveLoginLog(username, LoginType.LOGIN_SUCCESS.code(),LoginType.LOGIN_SUCCESS.msg(),loginSourceType.code());
        }
        return tokenUtil.createTokenByLoginUser(loginUser);
    }

    /**
     * 获取用户登陆凭证
     * @param phoneNumber 手机号
     * @return 登陆凭证
     */
    public String getLoginToken(String phoneNumber){
        // 根据手机号查询数据库，判断用户是否存在
        User user = userService.selectUserByMobile(phoneNumber);
        if (user == null) {
            // 如果查询的用户为空，则表示没有注册过，则需要注册信息入库
            user = new User();
            Long userId = IdUtil.getSnowflake().nextId();
            user.setUserId(userId);
            user.setUsername(phoneNumber);
            String newPassword = SecurityUtil.encryptPassword(RandomUtil.randomString(12));
            user.setPassword(newPassword);
            user.setName(phoneNumber);
            user.setPhoneNumber(phoneNumber);
            user.setIsRoot(false);
            userService.insertUser(user);
        }
        LoginUser loginUser = getLoginUserByUser(user, LoginSourceType.ANDROID_LOGIN);
        saveLoginLog(loginUser.getUsername(), LoginType.LOGIN_SUCCESS.code(),LoginType.LOGIN_SUCCESS.msg(),LoginSourceType.ANDROID_LOGIN.code());
        //设置用户代理信息
        setUserAgent(loginUser);
        return tokenUtil.createTokenByLoginUser(loginUser);
    }

    /**
     * 获取登陆用户信息
     * @param user 用户
     * @param loginSourceType 访问来源
     * @return 登陆用户信息
     */
    private LoginUser getLoginUserByUser(User user, LoginSourceType loginSourceType) {
        LoginUser loginUser = JSONUtil.parse(user).toBean(LoginUser.class);
        loginUser.setLoginSource(loginSourceType.code());
        Set<String> funcPermissions = menuService.selectPermissionByUserId(user.getUserId());
        if(funcPermissions == null){
            funcPermissions = new HashSet<>();
        }
        loginUser.setFuncPermissions(funcPermissions);
        List<DataPermission> dataPermissions = new ArrayList<>();
        for(Role role : user.getRoles()){
            DataPermission dataPermission = JSONUtil.parse(role).toBean(DataPermission.class);
            dataPermissions.add(dataPermission);
        }
        loginUser.setDataPermissions(dataPermissions);
        return loginUser;
    }

    /**
     * 设置用户代理信息
     * @param loginUser 登录信息
     */
    private void setUserAgent(LoginUser loginUser) {
        String userAgentStr = ServletUtil.getRequest().getHeader(HttpHeaders.USER_AGENT);
        log.info("User-Agent：{}.", userAgentStr);
        UserAgent userAgent = UserAgentUtil.parse(userAgentStr);
        loginUser.setBrowser(userAgent.getBrowser().toString());
        loginUser.setVersion(userAgent.getVersion());
        loginUser.setOs(userAgent.getPlatform().toString()+" "+userAgent.getOsVersion());
        String ip = IpUtil.getIpAddr(ServletUtil.getRequest());
        loginUser.setIpAddr(ip);
    }

    private void saveLoginLog(String username, Integer status, String message, Integer loginSource) {
        LoginLog loginLog = new LoginLog();
        Long loginId = IdUtil.getSnowflake().nextId();
        loginLog.setLoginId(loginId);
        loginLog.setUsername(username);
        loginLog.setStatus(status);
        loginLog.setMsg(message);
        loginLog.setLoginSource(loginSource);
        setUserAgent(loginLog);
        loginLogService.insertLoginLog(loginLog);
    }

    private void setUserAgent(LoginLog loginLog){
        String userAgentStr = ServletUtil.getRequest().getHeader(HttpHeaders.USER_AGENT);
        UserAgent userAgent = UserAgentUtil.parse(userAgentStr);
        // 获取客户端IP
        String ip = IpUtil.getIpAddr(ServletUtil.getRequest());
        loginLog.setIpaddr(ip);
        // 获取登陆属地
        String loginLocation = IpUtil.getRealAddressByIP(ip);
        loginLog.setLoginLocation(loginLocation);
        // 获取客户端操作系统
        String os = userAgent.getPlatform().toString()+" "+userAgent.getOsVersion();
        loginLog.setOs(os);
        // 获取客户端浏览器
        String browser = userAgent.getBrowser().getName();
        loginLog.setBrowser(browser);
    }
}
